<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Loop (read file contents)</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
</head>
<body>

<h1>Loop (read file contents)</h1>

<p>Retrieves the lines in a text file, one at a time (performs better than <a href="FileReadLine.htm">FileReadLine</a>).</p>

<pre class="Syntax">Loop, Read, InputFile [, OutputFile]</pre>
<h3>Parameters</h3>
<dl>

  <dt>Read</dt>
  <dd><p>This parameter must be the word READ.</p></dd>

  <dt>InputFile</dt>
  <dd><p>The name of the text file whose contents will be read by the loop, which is assumed to be in <a href="../Variables.htm#WorkingDir">%A_WorkingDir%</a> if an absolute path isn't specified. Windows and Unix formats are supported; that is, the file's lines may end in either carriage return and linefeed (`r`n) or just linefeed (`n).</p></dd>

  <dt>OutputFile</dt>
  <dd><p>(Optional) The name of the file to be kept open for the duration of the loop, which is assumed to be in <a href="../Variables.htm#WorkingDir">%A_WorkingDir%</a> if an absolute path isn't specified.</p>
      <p>Within the loop's body, use the <a href="FileAppend.htm">FileAppend</a> command with only one parameter (the text to be written) to append to this special file. Appending to a file in this manner performs better than using <a href="FileAppend.htm">FileAppend</a> in its 2-parameter mode because the file does not need to be closed and re-opened for each operation. Remember to include a linefeed (`n) after the text, if desired.</p>
      <p>The file is not opened if nothing is ever written to it. This happens if the Loop performs zero iterations or if it never uses the <a href="FileAppend.htm">FileAppend</a> command.</p>
      <p><strong>Binary mode</strong>: To append in binary mode rather than text mode, prepend an asterisk to the filename. This causes each linefeed character (`n) to be written as a single linefeed (LF) rather than the Windows standard of CR+LF. For example: <code><strong>*</strong>C:\My Unix File.txt</code>. Even without the asterisk, binary mode is put into effect automatically if the Loop's <u>first</u> use of <a href="FileAppend.htm">FileAppend</a> writes any carriage return and linefeed pairs (`r`n).</p>      
      <p><strong>Standard Output (stdout)</strong>: Specifying an asterisk (*) for <em>OutputFile</em> sends any text written by <a href="FileAppend.htm">FileAppend</a> to standard output (stdout). Although such output can be redirected to a file, piped to another EXE, or captured by <a href="_ErrorStdOut.htm">fancy text editors</a>, it will not appear at the command prompt it was launched from. See <a href="FileAppend.htm">FileAppend</a> for more details.</p>
      <p><strong>Escaped Commas</strong>: Unlike the last parameter of most other commands, commas in <em>OutputFile</em> must be escaped (`,).</p></dd>

</dl>

<h3>Remarks</h3>
<p>A file-reading loop is useful when you want to operate on each line contained in a text file, one at a time. It performs better than using <a href="FileReadLine.htm">FileReadLine</a> because: 1) the file can be kept open for the entire operation; and 2) the file does not have to be re-scanned each time to find the requested line number.</p>
<p><a name="LoopReadLine"></a>The built-in variable <strong>A_LoopReadLine</strong> exists within any file-reading loop. It contains the contents of the current line excluding the carriage return and linefeed (`r`n) that marks the end of the line. If an inner file-reading loop is enclosed by an outer file-reading loop, the innermost loop's file-line will take precedence.</p>
<p>Lines up to 65,534 characters long can be read. If the length of a line exceeds this, its remaining characters will be read during the next loop iteration.</p>
<p><a href="StringSplit.htm">StringSplit</a> or a <a href="LoopParse.htm">parsing loop</a> is often used inside a file-reading loop to parse the contents of each line retrieved from <em>InputFile</em>. For example, if <em>InputFile</em>'s lines are each a series of tab-delimited fields, those fields can individually retrieved as in this example:</p>
<pre>Loop, read, C:\Database Export.txt
{
    Loop, parse, A_LoopReadLine, %A_Tab%
    {
        MsgBox, Field number %A_Index% is %A_LoopField%.
    }
}</pre>
<p>To load an entire file into variable, use <a href="FileRead.htm">FileRead</a> because it performs much better than a loop (especially for large files).</p>
<p>To have multiple files open simultaneously, use DllCall() as shown in <a href="DllCall.htm#file">this example</a>.</p>
<p>See <a href="Loop.htm">Loop</a> for information about <a href="Block.htm">Blocks</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, and the A_Index variable (which exists in every type of loop).</p>
<p>To control how the file is decoded when no byte order mark is present, use <a href="FileEncoding.htm">FileEncoding</a>.</p>

<h3>Related</h3>
<p><a href="FileEncoding.htm">FileEncoding</a>, <a href="FileOpen.htm">FileOpen</a>/<a href="../objects/File.htm">File Object</a>, <a href="FileRead.htm">FileRead</a>, <a href="FileReadLine.htm">FileReadLine</a>, <a href="FileAppend.htm">FileAppend</a>, <a href="Sort.htm">Sort</a>, <a href="Loop.htm">Loop</a>, <a href="Break.htm">Break</a>, <a href="Continue.htm">Continue</a>, <a href="Block.htm">Blocks</a>, <a href="FileSetAttrib.htm">FileSetAttrib</a>, <a href="FileSetTime.htm">FileSetTime</a></p>

<h3>Examples</h3>
<pre class="NoIndent"><em>; Example #1: Only those lines of the 1st file that contain the word FAMILY will be written to the 2nd file.
; Uncomment the first line to overwrite rather than append to any existing file.
;FileDelete, C:\Docs\Family Addresses.txt</em>

Loop, read, C:\Docs\Address List.txt, C:\Docs\Family Addresses.txt
{
    IfInString, A_LoopReadLine, family, FileAppend, %A_LoopReadLine%`n
}</pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; Example #2: Retrieve the last line from a text file.</em>
Loop, read, C:\Log File.txt
    last_line := A_LoopReadLine  <em>; When loop finishes, this will hold the last line.</em></pre>
<p>&nbsp;</p>
<pre class="NoIndent"><em>; Example #3: A working script that attempts to extract all FTP and HTTP
; URLs from a text or HTML file:</em>
FileSelectFile, SourceFile, 3,, Pick a text or HTML file to analyze.
if SourceFile =
    return  <em>; This will exit in this case.</em>

SplitPath, SourceFile,, SourceFilePath,, SourceFileNoExt
DestFile = %SourceFilePath%\%SourceFileNoExt% Extracted Links.txt

IfExist, %DestFile%
{
    MsgBox, 4,, Overwrite the existing links file? Press No to append to it.`n`nFILE: %DestFile%
    IfMsgBox, Yes
        FileDelete, %DestFile%
}

LinkCount = 0
Loop, read, %SourceFile%, %DestFile%
{
    URLSearchString = %A_LoopReadLine%
    Gosub, URLSearch
}
MsgBox %LinkCount% links were found and written to &quot;%DestFile%&quot;.
return


URLSearch:
<em>; It's done this particular way because some URLs have other URLs embedded inside them:</em>
StringGetPos, URLStart1, URLSearchString, http://
StringGetPos, URLStart2, URLSearchString, ftp://
StringGetPos, URLStart3, URLSearchString, www.

<em>; Find the left-most starting position:</em>
URLStart = %URLStart1%  <em>; Set starting default.</em>
Loop
{
    <em>; It helps performance (at least in a script with many variables) to resolve</em>
    <em>; &quot;URLStart%A_Index%&quot; only once:</em>
    ArrayElement := URLStart%A_Index%
    if ArrayElement =  <em>; End of the <a href="../misc/Arrays.htm#pseudo">pseudo-array</a> has been reached.</em>
        break
    if ArrayElement = -1  <em>; This element is disqualified.</em>
        continue
    if URLStart = -1
        URLStart = %ArrayElement%
    else <em>; URLStart has a valid position in it, so compare it with ArrayElement.</em>
    {
        if ArrayElement &lt;&gt; -1
            if ArrayElement &lt; %URLStart%
                URLStart = %ArrayElement%
    }
}

if URLStart = -1  <em>; No URLs exist in URLSearchString.</em>
    return

<em>; Otherwise, extract this URL:</em>
StringTrimLeft, URL, URLSearchString, %URLStart%  <em>; Omit the beginning/irrelevant part.</em>
Loop, parse, URL, %A_Tab%%A_Space%&lt;&gt;  <em>; Find the first space, tab, or angle (if any).</em>
{
    URL = %A_LoopField%
    break  <em>; i.e. perform only one loop iteration to fetch the first &quot;field&quot;.</em>
}
<em>; If the above loop had zero iterations because there were no ending characters found,
; leave the contents of the URL var untouched.</em>

<em>; If the URL ends in a double quote, remove it.  For now, StringReplace is used, but
; note that it seems that double quotes can legitimately exist inside URLs, so this
; might damage them:</em>
StringReplace, URLCleansed, URL, &quot;,, All
FileAppend, %URLCleansed%`n
LinkCount += 1

<em>; See if there are any other URLs in this line:</em>
StringLen, CharactersToOmit, URL
CharactersToOmit += %URLStart%
StringTrimLeft, URLSearchString, URLSearchString, %CharactersToOmit%
Gosub, URLSearch  <em>; Recursive call to self.</em>
return</pre>

</body>
</html>
